app.py
from flask import Flask, render_template, request, redirect, url_for, flash, send_file, session
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from flask_migrate import Migrate
import pandas as pd
import os
import io
import matplotlib.pyplot as plt
import base64
from flask_paginate import Pagination, get_page_parameter
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['UPLOAD_FOLDER'] = 'uploads'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(150), unique=True, nullable=False)
password = db.Column(db.String(150), nullable=False)
role = db.Column(db.String(50), nullable=False, default='User')
class UploadHistory(db.Model):
id = db.Column(db.Integer, primary_key=True)
filename = db.Column(db.String(150), nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
timestamp = db.Column(db.DateTime, nullable=False)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/', methods=['GET', 'POST'])
@login_required
def index():
if request.method == 'POST':
if 'file' not in request.files:
return redirect(request.url)
file = request.files['file']
if file.filename == '':
return redirect(request.url)
if file:
filepath = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
file.save(filepath)
new_upload = UploadHistory(filename=file.filename, user_id=current_user.id, timestamp=pd.Timestamp.now())
db.session.add(new_upload)
db.session.commit()
session['filepath'] = filepath
return redirect(url_for('index'))
filepath = session.get('filepath')
if filepath:
df = pd.read_csv(filepath)
page = request.args.get(get_page_parameter(), type=int, default=1)
per_page = 10
offset = (page - 1) * per_page
paginated_df = df[offset:offset + per_page]
img = io.BytesIO()
plt.figure(figsize=(10, 6))
plt.hist(df['column_of_interest'], bins=20, color='blue', edgecolor='black')
plt.title('數據分佈')
plt.xlabel('值')
plt.ylabel('頻率')
plt.grid(True)
plt.savefig(img, format='png')
img.seek(0)
plot_url = base64.b64encode(img.getvalue()).decode('utf8')
pagination = Pagination(page=page, total=len(df), per_page=per_page, css_framework='bootstrap4')
return render_template('index.html', tables=[paginated_df.to_html(classes='data')], pagination=pagination, plot_url=plot_url)
history = UploadHistory.query.filter_by(user_id=current_user.id).order_by(UploadHistory.timestamp.desc()).all()
return render_template('index.html', history=history)
@app.route('/download')
@login_required
def download():
filepath = session.get('filepath')
if filepath:
return send_file(filepath, as_attachment=True)
return redirect(url_for('index'))
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).first()
if user and user.password == password:
login_user(user)
return redirect(url_for('index'))
else:
flash('Login Unsuccessful. Please check username and password', 'danger')
return render_template('login.html')
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
role = request.form['role']
if User.query.filter_by(username=username).first():
flash('Username already exists.', 'danger')
else:
new_user = User(username=username, password=password, role=role)
db.session.add(new_user)
db.session.commit()
flash('Account created successfully! You can now log in.', 'success')
return redirect(url_for('login'))
return render_template('register.html')
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('login'))
if __name__ == '__main__':
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home - Day 15</title>
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<header>
<h1>Welcome, {{ current_user.username }}!</h1>
<nav>
<ul>
<li><a href="{{ url_for('index') }}">Home</a></li>
<li><a href="{{ url_for('logout') }}">Logout</a></li>
</ul>
</nav>
</header>
<main>
<h2>User History</h2>
{% if history %}
<ul>
{% for item in history %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% else %}
<p>No history available.</p>
{% endif %}
</main>
<footer>
<p>© 2024 Your Flask Application</p>
</footer>
</body>
</html>
admin.html
<h1>Admin Panel</h1>
<table>
<tr>
<th>Filename</th>
<th>User ID</th>
<th>Timestamp</th>
</tr>
{% for upload in uploads %}
<tr>
<td>{{ upload.filename }}</td>
<td>{{ upload.user_id }}</td>
<td>{{ upload.timestamp }}</td>
</tr>
{% endfor %}
</table>